/*  功能：时钟模块
 */
#include "bsp_DS1302.h"
#include "User_App.h"

#include "bsp_Timer.h"

struct TIMEData TimeData_t;
uint16_t g_rtctick;
void Delay_us(uint32_t us); // 简单的延时函数

void DS1302_GPIO_Init() // IO,CE,SCLK端口初始化
{
    // LL_GPIO_SetPinMode(RTC_CLK_PORT, RTC_CLK_PIN, LL_GPIO_MODE_OUTPUT);
    // LL_GPIO_SetPinPull(RTC_CLK_PORT, RTC_CLK_PIN, LL_GPIO_PULL_DOWN);
    // LL_GPIO_SetPinMode(RTC_RST_PORT, RTC_RST_PIN, LL_GPIO_MODE_OUTPUT);
    // LL_GPIO_SetPinPull(RTC_RST_PORT, RTC_RST_PIN, LL_GPIO_PULL_NO);
    // LL_GPIO_SetPinMode(RTC_DAT_PORT, RTC_DAT_PIN, LL_GPIO_MODE_OUTPUT);
    // LL_GPIO_SetPinPull(RTC_DAT_PORT, RTC_DAT_PIN, LL_GPIO_PULL_DOWN);
}

/* @description: 传递一个字节
 * @event:
 * @param {uint8_t} _data
 * @return {*}
 */
static void Send_OneByte(uint8_t _data)
{
    uint8_t temp = _data;
    for (uint8_t i = 0; i < 8; i++)
    {
        if (temp & 0x01)
        {
            DATA_H;
        } // IO=1;
        else
        {
            DATA_L;
        } // IO=0;
        temp = temp >> 1;
        Delay_us(1); // for tcc
        SCLK_H;      // CLK=1;
        Delay_us(1); // for tch
        SCLK_L;      // CLK=0;
    }
}
/* @description: 向指定寄存器发送一个字节数据
 * @event:
 * @param {uint8_t} _address
 * @param {uint8_t} _data
 * @return {*}
 */
static void DS1302_Wirte_Reg(uint8_t _address, uint8_t _data)
{
    uint8_t temp1, temp2;
    temp1 = _address;
    temp2 = _data;
    LL_GPIO_SetPinMode(RTC_DAT_PORT, RTC_DAT_PIN, LL_GPIO_MODE_OUTPUT);
    LL_GPIO_SetPinPull(RTC_DAT_PORT, RTC_DAT_PIN, LL_GPIO_PULL_DOWN);

    CE_H; // RET=1;
    Delay_us(3);
    // 发送地址
    Send_OneByte(temp1);

    // 发送数据
    Send_OneByte(temp2);
    DATA_L;
    CE_L; // RET=0;
}
/* @description: 从指定地址读取一字节数据
 * @event:
 * @param {uint8_t} _address
 * @return {*}
 */
uint8_t DS1302_Read_Reg(uint8_t _address)
{

    uint8_t recdata;
    uint8_t temp = _address;
    uint8_t retnum;

    LL_GPIO_SetPinMode(RTC_DAT_PORT, RTC_DAT_PIN, LL_GPIO_MODE_OUTPUT);
    LL_GPIO_SetPinPull(RTC_DAT_PORT, RTC_DAT_PIN, LL_GPIO_PULL_DOWN);

    CE_H; // RET=1;
          // 写地址
    for (uint8_t i = 0; i < 8; i++)
    {
        if (temp & 0x01)
        {
            DATA_H;
        } // IO=1;
        else
        {
            DATA_L;
        } // IO=0;
        temp = temp >> 1;
        Delay_us(1);
        SCLK_H; // CLK=1;
        Delay_us(1);
        if (i == 7)
        {
            LL_GPIO_SetPinMode(RTC_DAT_PORT, RTC_DAT_PIN, LL_GPIO_MODE_INPUT);
            LL_GPIO_SetPinPull(RTC_DAT_PORT, RTC_DAT_PIN, LL_GPIO_PULL_DOWN);
        }
        SCLK_L; // CLK=0;
    }
    // 读数据

    for (uint8_t i = 0; i < 8; i++)
    {
        recdata = recdata >> 1; // 读数据变量
        if (GPIO_ReadInputDataBit(RTC_DAT_PORT, RTC_DAT_PIN))
        {
            recdata = recdata | 0x80;
        }
        else // IO=0
        {
            recdata = recdata & 0x7f;
        }
        SCLK_H; // CLK=1;
        Delay_us(1);
        SCLK_L; // CLK=0;
    }
    CE_L; // RET=0;
    LL_GPIO_SetPinMode(RTC_DAT_PORT, RTC_DAT_PIN, LL_GPIO_MODE_OUTPUT);
    LL_GPIO_SetPinPull(RTC_DAT_PORT, RTC_DAT_PIN, LL_GPIO_PULL_DOWN);
    // 配置IO为输出,恢复正常状态

    // 数据处理转化十进制
    retnum = BCD_TO_DEC(recdata);
    return retnum;
}

void DS1302_Init()
{
    DS1302_GPIO_Init();
    /*芯片上电后先读取一次RTC值*/
    TimeData_t.second = DS1302_Read_Reg(0x81); // 读秒
    TimeData_t.minute = DS1302_Read_Reg(0x83); // 读分
    TimeData_t.hour = DS1302_Read_Reg(0x85);   // 读时
    TimeData_t.day = DS1302_Read_Reg(0x87);    // 读日
    TimeData_t.month = DS1302_Read_Reg(0x89);  // 读月
    TimeData_t.week = DS1302_Read_Reg(0x8B);   // 读星期
    TimeData_t.year = DS1302_Read_Reg(0x8D);   // 读年

    DS1302_Wirte_Reg(0x8e, 0x00); // 关闭写保护
#ifdef CHARGE_INTERNAL            /*开启内部充电*/
    DS1302_Wirte_Reg(0x90, 0xA5);
#endif
    DS1302_Wirte_Reg(0x80, (((TimeData_t.second / 10) << 4) | (TimeData_t.second % 10)) & 0x7f);
    DS1302_Wirte_Reg(0x8e, 0x80); // 写保护
}

void DS1302_Read_Time()
{
    TimeData_t.second = DS1302_Read_Reg(0x81); // 读秒
    TimeData_t.minute = DS1302_Read_Reg(0x83); // 读分
    TimeData_t.hour = DS1302_Read_Reg(0x85);   // 读时
    TimeData_t.day = DS1302_Read_Reg(0x87);    // 读日
    TimeData_t.month = DS1302_Read_Reg(0x89);  // 读月
    TimeData_t.week = DS1302_Read_Reg(0x8B);   // 读星期
    TimeData_t.year = DS1302_Read_Reg(0x8D);   // 读年
}

/*  @brief  设置时间数据
    @param  variable_01
            变量1
    @return 无
    @property 例：设置日期为29号， DS1302_Set_Time(DAY, 0X29)
*/
void DS1302_Set_Time(TIMEDATA_E _timedata_e, uint8_t _value)
{
    uint8_t temp;
    temp = DEC_TO_BCD(_value);
    DS1302_Wirte_Reg(0x8e, 0x00); // 关闭写保护
    switch (_timedata_e)
    {
    case YEAR:
        DS1302_Wirte_Reg(0x8c, temp);
        break;
    case MONTH:
        DS1302_Wirte_Reg(0x88, temp);
        break;
    case DAY:
        DS1302_Wirte_Reg(0x86, temp);
        break;
    case HOUR:
        DS1302_Wirte_Reg(0x84, temp);
        break;
    case MINUTE:
        DS1302_Wirte_Reg(0x82, temp);
        break;
    case SECOND:
        DS1302_Wirte_Reg(0x80, temp);
        break;
    case WEEK:
        DS1302_Wirte_Reg(0x8a, temp);
        break;
    default:
        break;
    }
    DS1302_Wirte_Reg(0x8e, 0x80); // 打开写保护
}

void Delay_us(uint32_t us) // 简单的延时函数
{
    // uint32_t ticks = us * (SystemCoreClock / 8000000); // 计算需要的SysTick时钟周期数
    // SysTick->LOAD = ticks;                             // 重新加载值寄存器
    // SysTick->VAL = 0UL;                                // 当前值寄存器
    // SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;           // 控制
    // while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0)
    //     ;              // 等待计数完成
    // SysTick->CTRL = 0; // 控制 关闭SysTick计数器
    for (uint8_t i = 0; i < (30 * us); i++)
    {
        __nop();
    }
}
extern bsp_TIM_t *Ti_RUN_LED;

void bsp_DS1302_Debug(void)
{
    bsp_TIM_t Ti_Clock_Debug;
    // OLED_Init(); // 初始化OLED
    DS1302_Init();
#if 0
    // 设置时间
    DS1302_Set_Time(YEAR, 25);   // 年
    DS1302_Set_Time(MONTH, 5);   // 月
    DS1302_Set_Time(DAY, 9);     // 日
    DS1302_Set_Time(HOUR, 23);   // 时
    DS1302_Set_Time(MINUTE, 05); // 分
    DS1302_Set_Time(SECOND, 00); // 秒
#endif

    Ti_obj_New(&Ti_Clock_Debug, 500, Ti_RUN, DS1302_Read_Time);

    while (1)
    {
        bsp_Ti_All_Handle();
        // Delay_us(10);
        // LL_GPIO_TogglePin(RTC_RST_PORT, RTC_RST_PIN); // 翻转运行指示灯
    }
}
